package xinhao.lr.lr0;

import xinhao.Grammar;
import xinhao.Production;
import xinhao.Symbol;
import xinhao.Utils;
import xinhao.ll.FollowSet;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author by xinhao  2021/8/23
 */
public class SLRUtils {

    /**
     * 得到文法对应的 SLR 分析表 actionMap 和 gotoMap
     * @param grammar
     * @param allItemSetList
     * @param actionMap
     * @param gotoMap
     */
    private static void createSLRTable(Grammar grammar, List<ProductionItemSet> allItemSetList,
                                       Map<ProductionItemSet, Map<Symbol, Action>> actionMap,
                                       Map<ProductionItemSet, Map<Symbol, ProductionItemSet>> gotoMap) {
        // 获取文法的后继符号集
        Map<Symbol, FollowSet> followSetMap = grammar.getFollowSetMap();
        // 开始符号
        Symbol start = grammar.getStart();
        // 所有的非终结符
        Set<Symbol> vtSymbols = grammar.getVtSet();
        // 将结束符号添加进去
        vtSymbols.add(Symbol.END);
        // 遍历文法所有的项目集
        for (ProductionItemSet itemSet : allItemSetList) {
            // 遍历项目集中的项目
            for (ProductionItem item : itemSet.getItemSet()) {
                // 得到当前项目 pos 位置的符号
                Symbol posSymbol = item.getPosSymbol();
                // 如果是非终结符，那么就要添加到 gotoMap 中
                if (!posSymbol.isTerminator()) {
                    Utils.addToDoubleMapPrintConflict(gotoMap, itemSet, posSymbol, LR0Utils.Goto(itemSet, posSymbol, grammar),
                            "gotoMap 有冲突: old: %s, new: %s");
                } else {
                    // 是终结符但不是结束符号 END
                    if (!Symbol.END.equals(posSymbol)) {
                        // 获取后继项目集
                        ProductionItemSet nextItemSet = LR0Utils.Goto(itemSet, posSymbol, grammar);
                        // 想 action 中添加移入操作action
                        Utils.addToDoubleMapPrintConflict(actionMap, itemSet, posSymbol, Action.createS(nextItemSet),
                                "actionMap 有冲突: old: %s,  new: %s");
                    } else {
                        // 当前项目是 aBb• 格式，说明需要归约，这个就是归约需要的产生式
                        Production production = item.getProduction();
                        // 如果产生式左部和开始符号相同，说明是总结了，添加 acc 的action
                        if (start.equals(production.getLeft())) {
                            Utils.addToDoubleMapPrintConflict(actionMap, itemSet, posSymbol, Action.createAcc(),
                                    "actionMap 有冲突: old: %s,  new: %s");
                        } else {
//                            /**
//                             * 在LR0 算法中，对于  aBb• 这类项目，只要它对应的产生式不是开始符号的产生式
//                             * 那么遇到任意终结符包括终止符号$ 都进行归约。
//                             * 但是这种方式是会有冲突的，例如:
//                             * 1. 对于同一个项目集 itemSet 中有两个项目 S-> a• 和 S-> a•b,
//                             *    遇到终结符b，那么既可以归约，又可以移入，这就是移入-归约冲突
//                             * 2. 对于同一个项目集 itemSet 中有两个项目 S-> a• 和 A-> b•
//                             *    两个项目都可以归约，但是归约的产生式不同，这个时候就是归约-归约冲突
//                             */
//                            for (Symbol symbol : vtSymbols) {
//                                Utils.addToDoubleMapPrintConflict(actionMap, itemSet, symbol, Action.createR(production),
//                                        "actionMap 有冲突: old: %s,  new: %s");
//                            }


                            /**
                             * 在SLR 算法中，对于  aBb• 这类项目，只要它对应的产生式不是开始符号的产生式
                             * 那么只有遇到产生式左部符号的后继符号集才能都进行归约。
                             * 这样SLR 与 LR0 对比，它进行归约的操作少的多。
                             */
                            FollowSet followSet = followSetMap.get(production.getLeft());
                            for (Symbol symbol : followSet.getSet()) {
                                Utils.addToDoubleMapPrintConflict(actionMap, itemSet, symbol, Action.createR(production),
                                        "actionMap 有冲突: old: %s,  new: %s");
                            }
                        }
                    }
                }
            }
        }
    }


}
